﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SafeScript.MetaModel.Statements;

namespace SafeScript.MetaModel
{
    public class Constructor : MemberFunction
    {
        public List<Operator> SuperParameters = new List<Operator>();
        public bool IsGenericConstructor = false;
        public Constructor BaseConstructor;

        public void ComputeSuperType(ErrorReport report)
        {
            Class cl = this.Owner as Class;
            if (cl.BaseClass != null && !(cl.BaseClass is ObjectType))
            {
                // Get a list of the parameters passed to the function
                List<ITypeDef> parameterTypes = new List<ITypeDef>();
                // Compute the types of all parameters passed to the super constructor
                foreach (Operator op in this.SuperParameters)
                {
                    ITypeDef optype = op.ComputeType(null, false, report);
                    if (optype == null)
                        return;
                    parameterTypes.Add(optype);
                }

                object obj = cl.BaseClass.GetConstructor();
                // Only one constructor?
                if (obj is Constructor)                
                    this.BaseConstructor = obj as Constructor;
                // Set of constructors?
                else if (obj is MemberFunctionSet )
                {
                    MemberFunctionSet set = obj as MemberFunctionSet;
                    this.BaseConstructor = set.Type.FindFunction(parameterTypes, report, this.Node) as Constructor;
                }
                // No constructor?
                if (this.BaseConstructor == null)
                {
                    report.Add(new ErrorEntry(this.Node) { Type = ErrorType.NoMatchingConstructor });
                    return;
                }

                // Does the number of parameters match?
                if (this.SuperParameters.Count != this.BaseConstructor.ParameterTypes.Count)
                {
                    report.Add(new ErrorEntry(this.Node) { Type = ErrorType.FunctionParameterCountMismatch });
                    return;
                }

                // Check each parameter
                for (var i = 0; i < parameterTypes.Count; ++i)
                {
                    // Type according to the function signature
                    ITypeDef t = this.BaseConstructor.ParameterTypes[i];
                    // Type of the value passed to the function parameter
                    ITypeDef optype = parameterTypes[i];
                    if (!optype.CanBeAssignedTo(t))
                    {
                        report.Add(new ErrorEntry(this.SuperParameters[i].Node) { Type = ErrorType.FunctionParameterTypeMismatch, Info = i.ToString() });
                        return;
                    }
                }
            }
        }
    }
}
